package com.xyz.study.netty.guide.nio;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * TimeClientHandler
 *
 * @author xyz
 * @version 1.0.0
 * @since 2021/6/30
 */
public class TimeClientHandler implements Runnable{

    private String host;

    private int port;

    private SocketChannel socketChannel;

    private Selector selector;

    private volatile boolean stop;

    public TimeClientHandler(String host, int port) {
        this.host = host;
        this.port = port;
        try {
            this.selector = Selector.open();
            this.socketChannel = SocketChannel.open();
            this.socketChannel.configureBlocking(false);
        }catch (Exception e){
            e.printStackTrace();
            System.exit(1);
        }
    }

    public void stop(){
        this.stop = true;
    }

    @Override
    public void run() {
        try{
            doConnect(this.host, this.port);
        } catch (Exception e){
            e.printStackTrace();
            System.exit(1);
        }

        while(!stop){
            try{
                this.selector.select(1000);
                Set<SelectionKey> selectionKeySet = selector.selectedKeys();
                Iterator<SelectionKey> selectionKeyIterator = selectionKeySet.iterator();
                while (selectionKeyIterator.hasNext()){
                    SelectionKey selectionKey = selectionKeyIterator.next();
                    selectionKeyIterator.remove();
                    handleInput(selectionKey);
                }
            } catch (Exception e){
                e.printStackTrace();
            }

        }
    }


    /**
     * 连接服务并发送数据
     * @param host
     * @param port
     * @return
     */
    private void doConnect(String host, int port) throws Exception{
        socketChannel.connect(new InetSocketAddress(host, port));
        socketChannel.register(selector, SelectionKey.OP_CONNECT);
    }

    private void handleInput(SelectionKey selectionKey) throws Exception{
        if (selectionKey.isValid()){
            SocketChannel sc = (SocketChannel) selectionKey.channel();
            if (selectionKey.isConnectable()){
                if (sc.finishConnect()){
                    doWrite(sc);
                    sc.register(selector, SelectionKey.OP_READ);
                }else {
                    System.exit(1);
                }
            }
            if (selectionKey.isReadable()){
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                int readBytes = sc.read(byteBuffer);
                if (readBytes > 0){
                    byteBuffer.flip();
                    byte[] bytes = new byte[byteBuffer.remaining()];
                    byteBuffer.get(bytes);
                    String body = new String(bytes, StandardCharsets.UTF_8);
                    System.out.println("Now is : " + body);
                    this.stop = true;
                }

            }
        }
    }

    private void doWrite(SocketChannel socketChannel) throws Exception{

        byte[] bytes = "QUERY TIME ORDER".getBytes();
        ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
        byteBuffer.put(bytes);
        byteBuffer.flip();
        socketChannel.write(byteBuffer);
        if (!byteBuffer.hasRemaining()){
            System.out.println("Send order 2 server succeed.");
        }
    }

}
